package org.pentaho.di.job.entries;

import org.apache.commons.lang.StringUtils;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.ShellAdapter;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.util.Utils;
import org.pentaho.di.i18n.BaseMessages;
import org.pentaho.di.job.JobMeta;
import org.pentaho.di.job.entry.JobEntryDialogInterface;
import org.pentaho.di.job.entry.JobEntryInterface;
import org.pentaho.di.repository.Repository;
import org.pentaho.di.ui.core.gui.WindowProperty;
import org.pentaho.di.ui.core.widget.TextVar;
import org.pentaho.di.ui.job.dialog.JobDialog;
import org.pentaho.di.ui.job.entry.JobEntryDialog;
import org.pentaho.di.ui.trans.step.BaseStepDialog;

/**
 * 
 * SQL Server备份还原作业项目界面对话框
 */
public class JobEntrySQLServerBakDialog extends JobEntryDialog implements JobEntryDialogInterface {

	/**
	 * 以此属性查找国际化文件，国际化文件位置规则： {包名}/messages/messages_{locale}.properties
	 */
	private static final Class<?> PKG = JobEntryBakProcessor.class; // for i18n purposes

	//SQL Server数据库备份还原配置信息
	private JobEntryBakProcessor meta;

	// flag saving the changed status of the job entry configuration object
	private boolean changed;

	/**
	 * 备份文件路径
	 */
	private Text bakFileText;

	/**
	 * 目标数据库主机
	 */
	private Text hostText;

	/**
	 * 目标数据库名称
	 */
	private Text dbNameText;

	/**
	 * 数据库端口
	 */
	private Text portText;

	/**
	 * 用户名
	 */
	private Text usernameText;

	/**
	 * 密码
	 */
	private Text passwdText;

	private Label bakFileLabel;

	private Button bakFileButton;

	private Group targetDBGroup;

	private FormData fdlFilename;

	private FormData fdbFilename;

	private FormData fdFilename;

	private FormData fdFileGroup;

	private TextVar targetDBNameText;

	/**
	 * 作业项名称
	 */
	private Text jobEntryNameText;
	/**
	 * The constructor should call super() and make sure that the name of the job
	 * entry is set.
	 * 
	 * @param parent
	 *            the SWT Shell to use
	 * @param jobEntryInt
	 *            the job entry settings object to use for the dialog
	 * @param rep
	 *            the repository currently connected to, if any
	 * @param jobMeta
	 *            the description of the job the job entry belongs to
	 */
	public JobEntrySQLServerBakDialog(Shell parent, JobEntryInterface jobEntryInt, Repository rep, JobMeta jobMeta) {
		super(parent, jobEntryInt, rep, jobMeta);
		// it is safe to cast the JobEntryInterface object to the object handled by this
		// dialog
		meta = (JobEntryBakProcessor) jobEntryInt;
		// ensure there is a default name for new job entries
		if (this.meta.getName() == null) {
			this.meta.setName(BaseMessages.getString(PKG, "JobEntrySQLBak.Default.Name"));
		}
	}

	/**
	 * This method is called by Spoon when the user opens the settings dialog of the
	 * job entry. It should open the dialog and return only once the dialog has been
	 * closed by the user.
	 * 
	 * If the user confirms the dialog, the meta object (passed in the constructor)
	 * must be updated to reflect the new job entry settings. The changed flag of
	 * the meta object must reflect whether the job entry configuration was changed
	 * by the dialog.
	 * 
	 * If the user cancels the dialog, the meta object must not be updated, and its
	 * changed flag must remain unaltered.
	 * 
	 * The open() method must return the met object of the job entry after the user
	 * has confirmed the dialog, or null if the user cancelled the dialog.
	 */
	public JobEntryInterface open() {
		// SWT code for setting up the dialog
		Shell parent = getParent();
		Display display = parent.getDisplay();

		shell = new Shell(parent, props.getJobsDialogStyle());
		shell.setSize(510, 290);
		//props.setLook(shell);
		JobDialog.setShellImage(shell, meta);

		// save the job entry's changed flag
		changed = meta.hasChanged();
		
		FormLayout formLayout = new FormLayout();
	    formLayout.marginWidth = Const.FORM_MARGIN;
	    formLayout.marginHeight = Const.FORM_MARGIN;
		shell.setLayout(formLayout);
		shell.setText(BaseMessages.getString(PKG, "JobEntrySQLBak.Shell.Title"));
		
		//组件修改监听，修改meta对象显示其属性是否被修改
		ModifyListener lsMod = new ModifyListener() {
			public void modifyText(ModifyEvent e) {
				meta.setChanged();
			}
		};
		
		int middle = props.getMiddlePct();
		int margin = Const.MARGIN;

	    // Filename line
	    Label jobEntryNameLabel = new Label( shell, SWT.RIGHT );
	    jobEntryNameLabel.setText("作业项名称：");
	    props.setLook( jobEntryNameLabel );
	    fdlFilename = new FormData();
	    fdlFilename.left = new FormAttachment( 0, 0 );
	    fdlFilename.top = new FormAttachment( 0, margin );
	    fdlFilename.right = new FormAttachment( middle, -margin );
	    jobEntryNameLabel.setLayoutData( fdlFilename );

	    jobEntryNameText = new Text(shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER );
	    props.setLook( jobEntryNameText );
	    jobEntryNameText.addModifyListener( lsMod );
	    fdFilename = new FormData();
	    fdFilename.left = new FormAttachment( middle, 0 );
	    fdFilename.top = new FormAttachment( 0, margin );
	    fdFilename.right = new FormAttachment( 100, 0 );
	    jobEntryNameText.setLayoutData( fdFilename );
		
	    // Filename line
	    bakFileLabel = new Label( shell, SWT.RIGHT );
	    bakFileLabel.setText("SQL Server备份文件：");
	    props.setLook( bakFileLabel );
	    fdlFilename = new FormData();
	    fdlFilename.left = new FormAttachment( 0, 0 );
	    fdlFilename.top = new FormAttachment( jobEntryNameText, margin);
	    fdlFilename.right = new FormAttachment( middle, -margin );
	    bakFileLabel.setLayoutData( fdlFilename );

	    bakFileButton = new Button( shell, SWT.PUSH | SWT.CENTER );
	    bakFileButton.setText("选择");
	    props.setLook( bakFileButton );
	    fdbFilename = new FormData();
	    fdbFilename.right = new FormAttachment( 100, 0 );
	    fdbFilename.top = new FormAttachment( jobEntryNameText, margin - 2 );
	    bakFileButton.setLayoutData( fdbFilename );
	    bakFileButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent arg0) {
				FileDialog dialog = new FileDialog(getParent());
				dialog.setFilterExtensions(new String[] {"*.bak", "*.*"});
				String file = dialog.open();
				if (StringUtils.isNotEmpty(file)) {
					bakFileText.setText(file);
				}
			}
	    	
		});
	    
	    bakFileText = new Text( shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER );
	    props.setLook( bakFileText );
	    bakFileText.addModifyListener( lsMod );
	    fdFilename = new FormData();
	    fdFilename.left = new FormAttachment( middle, 0 );
	    fdFilename.top = new FormAttachment( jobEntryNameText, margin );
	    fdFilename.right = new FormAttachment( bakFileButton, -margin );
	    bakFileText.setLayoutData( fdFilename );
	    
	    // Filename line
	    Label targetDBNameLabel = new Label( shell, SWT.RIGHT );
	    targetDBNameLabel.setText("目标数据库：");
	    props.setLook( targetDBNameLabel );
	    fdlFilename = new FormData();
	    fdlFilename.left = new FormAttachment( 0, 0 );
	    fdlFilename.top = new FormAttachment( bakFileText, margin );
	    fdlFilename.right = new FormAttachment( middle, -margin );
	    targetDBNameLabel.setLayoutData( fdlFilename );

	    targetDBNameText = new TextVar(meta, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER );
	    props.setLook( targetDBNameText );
	    targetDBNameText.addModifyListener( lsMod );
	    fdFilename = new FormData();
	    fdFilename.left = new FormAttachment( middle, 0 );
	    fdFilename.top = new FormAttachment( bakFileText, margin );
	    fdFilename.right = new FormAttachment( 100, 0 );
	    targetDBNameText.setLayoutData( fdFilename );
		
		
	    targetDBGroup = new Group( shell, SWT.SHADOW_NONE );
	    targetDBGroup.setText( "目标数据库信息" );
	    props.setLook( targetDBGroup );

	    FormLayout targetDBLayout = new FormLayout();
	    targetDBLayout.marginWidth = 10;
	    targetDBLayout.marginHeight = 10;
	    targetDBGroup.setLayout( targetDBLayout );
		
		Label hostLabel = new Label(targetDBGroup, SWT.RIGHT);
		hostLabel.setText("主机名称：");
		props.setLook( hostLabel );
	    fdlFilename = new FormData();
	    fdlFilename.left = new FormAttachment( 0, 0 );
	    fdlFilename.top = new FormAttachment( 0, margin );
	    fdlFilename.right = new FormAttachment( middle, -margin );
	    hostLabel.setLayoutData( fdlFilename );

		hostText = new Text(targetDBGroup, SWT.SINGLE | SWT.LEFT | SWT.BORDER | SWT.READ_ONLY);
		props.setLook( hostText );
	    fdFilename = new FormData();
	    fdFilename.left = new FormAttachment( middle, 0 );
	    fdFilename.top = new FormAttachment( 0, margin );
	    fdFilename.right = new FormAttachment( 100, 0 );
	    hostText.setLayoutData( fdFilename );
	    hostText.addModifyListener( lsMod );
	    hostText.setText("127.0.0.1");
	    hostText.setToolTipText("仅可恢复到本机，不支持远程恢复");
		
		Label dbNameLabel = new Label(targetDBGroup, SWT.RIGHT);
		dbNameLabel.setText("数据库名称：");
		props.setLook( dbNameLabel );
	    fdlFilename = new FormData();
	    fdlFilename.left = new FormAttachment( 0, 0 );
	    fdlFilename.top = new FormAttachment( hostText, margin );
	    fdlFilename.right = new FormAttachment( middle, -margin );
	    dbNameLabel.setLayoutData( fdlFilename );

		dbNameText = new Text(targetDBGroup, SWT.SINGLE | SWT.LEFT | SWT.BORDER | SWT.READ_ONLY);
		props.setLook( dbNameText );
		fdFilename = new FormData();
	    fdFilename.left = new FormAttachment( middle, 0 );
	    fdFilename.top = new FormAttachment( hostText, margin );
	    fdFilename.right = new FormAttachment( 100, 0 );
	    dbNameText.setLayoutData( fdFilename );
		dbNameText.addModifyListener(lsMod);
		dbNameText.setText("master");
		dbNameText.setToolTipText("默认连接到master数据库进行数据恢复");
		
		Label portLabel = new Label(targetDBGroup, SWT.RIGHT);
		portLabel.setText("端口号：");
		props.setLook( portLabel );
	    fdlFilename = new FormData();
	    fdlFilename.left = new FormAttachment( 0, 0 );
	    fdlFilename.top = new FormAttachment( dbNameText, margin );
	    fdlFilename.right = new FormAttachment( middle, -margin );
	    portLabel.setLayoutData( fdlFilename );

		portText = new Text(targetDBGroup, SWT.SINGLE | SWT.LEFT | SWT.BORDER);
		props.setLook( portText );
		fdFilename = new FormData();
	    fdFilename.left = new FormAttachment( middle, 0 );
	    fdFilename.top = new FormAttachment( dbNameText, margin );
	    fdFilename.right = new FormAttachment( 100, 0 );
	    portText.setLayoutData( fdFilename );
		portText.addModifyListener(lsMod);
		portText.setText("1433");

		Label usernameLabel = new Label(targetDBGroup, SWT.RIGHT);
		usernameLabel.setText("用户名：");
		props.setLook( usernameLabel );
	    fdlFilename = new FormData();
	    fdlFilename.left = new FormAttachment( 0, 0 );
	    fdlFilename.top = new FormAttachment( portText, margin );
	    fdlFilename.right = new FormAttachment( middle, -margin );
	    usernameLabel.setLayoutData( fdlFilename );

		usernameText = new Text(targetDBGroup, SWT.SINGLE | SWT.LEFT | SWT.BORDER);
		props.setLook( usernameText );
		fdFilename = new FormData();
	    fdFilename.left = new FormAttachment( middle, 0 );
	    fdFilename.top = new FormAttachment( portText, margin );
	    fdFilename.right = new FormAttachment( 100, 0 );
	    usernameText.setLayoutData( fdFilename );
		usernameText.addModifyListener(lsMod);
		usernameText.setText("sa");

		Label passwdLabel = new Label(targetDBGroup, SWT.RIGHT);
		passwdLabel.setText("密码：");
		props.setLook( passwdLabel );
	    fdlFilename = new FormData();
	    fdlFilename.left = new FormAttachment( 0, 0 );
	    fdlFilename.top = new FormAttachment( usernameText, margin );
	    fdlFilename.right = new FormAttachment( middle, -margin );
	    passwdLabel.setLayoutData( fdlFilename );

		passwdText = new Text(targetDBGroup, SWT.SINGLE | SWT.LEFT | SWT.BORDER);
		props.setLook( passwdText );
		fdFilename = new FormData();
	    fdFilename.left = new FormAttachment( middle, 0 );
	    fdFilename.top = new FormAttachment( usernameText, margin );
	    fdFilename.right = new FormAttachment( 100, 0 );
	    passwdText.setLayoutData( fdFilename );
		passwdText.addModifyListener(lsMod);
		passwdText.setText("");

	    fdFileGroup = new FormData();
	    fdFileGroup.left = new FormAttachment( 0, margin );
	    fdFileGroup.top = new FormAttachment( targetDBNameLabel, margin );
	    fdFileGroup.right = new FormAttachment( 100, -margin );
	    targetDBGroup.setLayoutData( fdFileGroup );
	    
		Button wOK = new Button(shell, SWT.PUSH);
		wOK.setText(BaseMessages.getString(PKG, "System.Button.OK"));
		Button wCancel = new Button(shell, SWT.PUSH);
		wCancel.setText(BaseMessages.getString(PKG, "System.Button.Cancel"));

		// 确定取消按钮放到窗口底部
		BaseStepDialog.positionBottomButtons(shell, new Button[] { wOK, wCancel }, margin, null);

		// 添加监听-取消
		Listener lsCancel = new Listener() {
			public void handleEvent(Event e) {
				cancel();
			}
		};

		// 添加监听-确定
		Listener lsOK = new Listener() {
			public void handleEvent(Event e) {
				ok();
			}
		};

		wCancel.addListener(SWT.Selection, lsCancel);
		wOK.addListener(SWT.Selection, lsOK);

		// default listener (for hitting "enter")
		SelectionAdapter lsDef = new SelectionAdapter() {
			public void widgetDefaultSelected(SelectionEvent e) {
				ok();
			}
		};
		
		//实现回车等同于点击确认
		jobEntryNameText.addSelectionListener(lsDef);

		// Detect X or ALT-F4 or something that kills this window and cancel the dialog
		// properly
		shell.addShellListener(new ShellAdapter() {
			public void shellClosed(ShellEvent e) {
				cancel();
			}
		});

		// populate the dialog with the values from the meta object
		populateDialog();

		// restore the changed flag to original value, as the modify listeners fire
		// during dialog population
		meta.setChanged(changed);

		// restore dialog size and placement, or set default size if none saved yet
		BaseStepDialog.setSize(shell, 600, 340, false);

		// open dialog and enter event loop
		shell.open();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}

		// at this point the dialog has closed, so either ok() or cancel() have been
		// executed
		return meta;
	}

	/**
	 * This helper method is called once the dialog is closed. It saves the
	 * placement of the dialog, so it can be restored when it is opened another
	 * time.
	 */
	private void dispose() {
		// save dialog window placement to use when reopened
		WindowProperty winprop = new WindowProperty(shell);
		props.setScreen(winprop);
		// close dialog window
		shell.dispose();
	}

	/**
	 * Copy information from the meta-data input to the dialog fields.
	 */
	public void populateDialog() {
		if (meta.getName() != null) {
			jobEntryNameText.setText(meta.getName());
		}
		if (meta.getBakfilename() != null) {
			bakFileText.setText(meta.getBakfilename());
		}
		if (meta.getTargetDBName() != null) {
			targetDBNameText.setText(meta.getTargetDBName());
		}
		if (meta.getHost() != null) {
			hostText.setText(meta.getHost());
		}
		if (meta.getDbname() != null) {
			dbNameText.setText(meta.getDbname());
		}
		if (meta.getPort() != null) {
			portText.setText(meta.getPort());
		}
		if (meta.getUser() != null) {
			usernameText.setText(meta.getUser());
		}
		if (meta.getPasswd() != null) {
			passwdText.setText(meta.getPasswd());
		}
	}

	/**
	 * 点击取消时执行，并将meta的内容改变设置为false
	 */
	private void cancel() {
		// restore changed flag on the meta object, any changes done by the modify
		// listener
		// are being revoked here
		meta.setChanged(changed);

		// this variable will be returned by the open() method, setting it to null, as
		// open() needs
		// to return null when the dialog is cancelled
		meta = null;

		// 关闭并销毁窗口
		dispose();
	}

	/**
	 * 点击确定按钮时执行此方法，仅当输入内容不为空时关闭窗口，并将meta的change设置为true,提示保存作业
	 */
	private void ok() {
		if (Utils.isEmpty(jobEntryNameText.getText())) {
			meta.setName(BaseMessages.getString(PKG, "JobEntrySQLBak.Default.Name"));
		} else {
			meta.setName(jobEntryNameText.getText());
		}
		if (Utils.isEmpty(bakFileText.getText())) {
			MessageBox mb = new MessageBox(shell, SWT.OK | SWT.ICON_ERROR);
			mb.setText(BaseMessages.getString(PKG, "System.StepJobEntryNameMissing.Title"));
			mb.setMessage(BaseMessages.getString(PKG, "System.JobEntryNameMissing.Msg"));
			mb.open();
			return;
		}
		if (Utils.isEmpty(targetDBNameText.getText())) {
			MessageBox mb = new MessageBox(shell, SWT.OK | SWT.ICON_ERROR);
			mb.setText(BaseMessages.getString(PKG, "System.StepJobEntryNameMissing.Title"));
			mb.setMessage(BaseMessages.getString(PKG, "System.JobEntryNameMissing.Msg"));
			mb.open();
			return;
		}
		if (Utils.isEmpty(hostText.getText())) {
			MessageBox mb = new MessageBox(shell, SWT.OK | SWT.ICON_ERROR);
			mb.setText(BaseMessages.getString(PKG, "System.StepJobEntryNameMissing.Title"));
			mb.setMessage(BaseMessages.getString(PKG, "System.JobEntryNameMissing.Msg"));
			mb.open();
			return;
		}
		if (Utils.isEmpty(portText.getText())) {
			MessageBox mb = new MessageBox(shell, SWT.OK | SWT.ICON_ERROR);
			mb.setText(BaseMessages.getString(PKG, "System.StepJobEntryNameMissing.Title"));
			mb.setMessage(BaseMessages.getString(PKG, "System.JobEntryNameMissing.Msg"));
			mb.open();
			return;
		}
		if (Utils.isEmpty(usernameText.getText())) {
			MessageBox mb = new MessageBox(shell, SWT.OK | SWT.ICON_ERROR);
			mb.setText(BaseMessages.getString(PKG, "System.StepJobEntryNameMissing.Title"));
			mb.setMessage(BaseMessages.getString(PKG, "System.JobEntryNameMissing.Msg"));
			mb.open();
			return;
		}
		if (Utils.isEmpty(passwdText.getText())) {
			MessageBox mb = new MessageBox(shell, SWT.OK | SWT.ICON_ERROR);
			mb.setText(BaseMessages.getString(PKG, "System.StepJobEntryNameMissing.Title"));
			mb.setMessage(BaseMessages.getString(PKG, "System.JobEntryNameMissing.Msg"));
			mb.open();
			return;
		}
		//将控件信息设置到meta中
		meta.setBakfilename(bakFileText.getText());
		meta.setTargetDBName(targetDBNameText.getText());
		meta.setHost(hostText.getText());
		meta.setDbname(dbNameText.getText());
		meta.setPort(portText.getText());
		meta.setUser(usernameText.getText());
		meta.setPasswd(passwdText.getText());
		meta.setChanged();
		// close dialog window and clean up
		dispose();
	}
}
